/**
  ******************************************************************************
  * @file CAN/Normal/main.c 
  * @author  MCD Application Team
  * @version  V3.0.0
  * @date  04/06/2009
  * @brief  Main program body
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  */ 

/* Includes ------------------------------------------------------------------*/
#include <applicfg.h>
#include "stm32f4xx.h"
#include "platform_config.h"

/* test_master */
#include "canfestival.h"
#include "Master.h"

/** @addtogroup StdPeriph_Examples
  * @{
  */

/** @addtogroup CAN_Normal
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define TIM4_start TIM4_Configuration

/* Private macro -------------------------------------------------------------*/
#define SEM_NUM 	( 1 )

/* Private variables ---------------------------------------------------------*/
CanTxMsg TxMessage;
CanRxMsg RxMessage;
OS_EVENT *recv_sem;
OS_EVENT *tran_sem;

/* Private function prototypes -----------------------------------------------*/
extern void TIM4_Configuration(void);
static void CAN_Configuration( u8 baudrate );
static u16  test_master(void);

u32 master_rcv_data = 0;

#define RX_BUF_LEN		1024
Message rx_msg_buf[RX_BUF_LEN];
u32	rx_save, rx_read;

#define TX_BUF_LEN		1024
u32 tx_save, tx_read;
CanTxMsg tx_msg_buf[TX_BUF_LEN];

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  can_master_init
  * @param  None
  * @retval None
  */
void can_master_init(void)
{
	rx_save = 0;
	rx_read = 0;

	tx_save = 0;
	tx_read = 0;

	CAN_Configuration(BAUDRATE_CAN_500k);

	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

/**
  * @brief  can_master_thread
  * @param  None
  * @retval None
  */
void can_recv_thread(void *pdata)
{
	u32 next;
	u8 err_sem;
	Message *pmsg;

	pdata = pdata;

	recv_sem = OSSemCreate(SEM_NUM);  
	tran_sem = OSSemCreate(SEM_NUM);  
	
	can_master_init();

	test_master();

	OSSemSet(recv_sem, 0, &err_sem);

	for(;;) // Infinite loop
	{	
		OSSemPend(recv_sem, 0, &err_sem);
			
		next = rx_read;
		pmsg = &rx_msg_buf[next];

    	// Disable the Interrupt sources
    	TIM4->DIER &= (u16)~TIM_IT_CC1;
		canDispatch(&TestMaster_Data, pmsg);
		// Enable the Interrupt sources
    	TIM4->DIER |= TIM_IT_CC1;

		next++;
		if(next >= RX_BUF_LEN) next = 0;
		rx_read = next;

		master_rcv_data = 0; 

		OSTimeDly(1);
	}
}

void can_send_thread(void *pdata)
{
	u32 next;
	u8 err_sem;
	u8  mailbox_no;
	CanTxMsg *ptx_msg;

	pdata = pdata;

	OSSemSet(tran_sem, 0, &err_sem);

	for(;;)
	{
		OSSemPend(tran_sem, 0, &err_sem);
		
		next = tx_read;
		ptx_msg = &tx_msg_buf[next];

		mailbox_no = CAN_Transmit(CAN1, ptx_msg);
		if(mailbox_no != CAN_NO_MB)
		{
			next++;
			if(next >= TX_BUF_LEN) next = 0;
			tx_read = next;			
		}
		else
		{
			OSSemPost(tran_sem);
		} 
		
		OSTimeDly(1);	
	}		
}

/**
  * @brief  Configures CAN.
  * @param  None
  * @retval : None
  */
static void CAN_Configuration( u8 baudrate )
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	CAN_InitTypeDef CAN_InitStructure;
	CAN_FilterInitTypeDef  CAN_FilterInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	// Connect CAN pins to AF9
	GPIO_PinAFConfig(GPIO_CAN, CAN_RX_SOURCE, CAN_AF_PORT);
	GPIO_PinAFConfig(GPIO_CAN, CAN_TX_SOURCE, CAN_AF_PORT); 
	
	// Configure CAN pin: RX
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_RX | GPIO_Pin_TX;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_Init(GPIO_CAN, &GPIO_InitStructure);

	// CAN register init
	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);

	/* CAN cell init */
	CAN_InitStructure.CAN_TTCM = DISABLE;
	CAN_InitStructure.CAN_ABOM = DISABLE;
	CAN_InitStructure.CAN_AWUM = DISABLE;
	CAN_InitStructure.CAN_NART = ENABLE;
	CAN_InitStructure.CAN_RFLM = DISABLE;
	CAN_InitStructure.CAN_TXFP = DISABLE;
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
	CAN_InitStructure.CAN_BS1 = CAN_BS1_10tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
	CAN_InitStructure.CAN_Prescaler = baudrate;
	CAN_Init(CAN1, &CAN_InitStructure);

	// CAN filter init
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterMode   = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale  = CAN_FilterScale_32bit;
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterIdLow  = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow  = 0x0000 | CAN_ID_EXT;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
	

	// transmit
	TxMessage.StdId = 0x321;
	TxMessage.ExtId = 0x00;
	TxMessage.RTR = CAN_RTR_DATA;
	TxMessage.IDE = CAN_ID_STD;
	TxMessage.DLC = 1;
}

u8 canSend(CAN_PORT notused, Message *m)
{
	u32	i;
	u32  next;

	next = tx_save + 1;
	if(next >= TX_BUF_LEN) next = 0;
	if(next != tx_read)
	{
		CanTxMsg *ptx_msg;

		ptx_msg = &tx_msg_buf[tx_save];
		ptx_msg->StdId = m->cob_id;

		if(m->rtr)
  			ptx_msg->RTR = CAN_RTR_REMOTE;
		else
			ptx_msg->RTR = CAN_RTR_DATA;

  		ptx_msg->IDE = CAN_ID_STD;
		ptx_msg->DLC = m->len;
		for(i = 0; i < m->len; i++)
			ptx_msg->Data[i] = m->data[i];

		tx_save = next;

		OSSemPost(tran_sem);
		return 0x00;  
	}

	return 0xFF;

}

void CAN1_RX0_IRQHandler(void) 
{
	Message *pmsg;
	u32 i, next;

	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);

	next = (rx_save + 1) ;
	if(next >= RX_BUF_LEN) next = 0;
	if(next == rx_read) return;

	pmsg = &rx_msg_buf[rx_save];
	pmsg->cob_id = (UNS16)RxMessage.StdId;	/**< message's ID */
	if(RxMessage.RTR == CAN_RTR_REMOTE)	/**< remote transmission request. (0 if not rtr message, 1 if rtr message) */
		pmsg->rtr = 1;		
	else
		pmsg->rtr = 0;

  	pmsg->len  = (UNS8)RxMessage.DLC;	/**< message's length (0 to 8) */
	for(i = 0; i < pmsg->len; i++)
		pmsg->data[i] = RxMessage.Data[i];

	rx_save = next;
	OSSemPost(recv_sem);
}

static TimerCallback_t init_callback;

UNS32 OnMasterMap1Update(CO_Data* d, const indextable * unsused_indextable, UNS8 unsused_bSubindex)
{
	//eprintf("OnMasterMap1Update:%d\n", MasterMap1);
	return 0;
}

s_BOARD MasterBoard = {"1", "500k"};

void help(void)
{
}

/***************************  INIT  *****************************************/
void InitNodes(CO_Data* d, UNS32 id)
{
	/****************************** INITIALISATION MASTER *******************************/
	if(strcmp(MasterBoard.baudrate, "none")){
 		RegisterSetODentryCallBack(&TestMaster_Data, 0x2000, 0, &OnMasterMap1Update);
		
		/* Defining the node Id */
		setNodeId(&TestMaster_Data, 0x01);

		/* init */
		setState(&TestMaster_Data, Initialisation);
	}
}

static void StartTimerLoop(TimerCallback_t _init_callback) 
{
	init_callback = _init_callback;

	SetAlarm(NULL, 0, init_callback, 0, 0);
	TIM4_start();
}

/***************************  EXIT  *****************************************/
void Exit(CO_Data* d, UNS32 id)
{
	if(strcmp(MasterBoard.baudrate, "none")){
		
		masterSendNMTstateChange(&TestMaster_Data, 0x01, NMT_Reset_Node);    
    
   	//Stop master
		setState(&TestMaster_Data, Stopped);
	}
}

/****************************************************************************/
/****************************  test_master  *********************************/
/****************************************************************************/
static u16 test_master(void)
{
	if(strcmp(MasterBoard.baudrate, "none"))
	{
		TestMaster_Data.heartbeatError = TestMaster_heartbeatError;
		TestMaster_Data.initialisation = TestMaster_initialisation;
		TestMaster_Data.preOperational = TestMaster_preOperational;
		TestMaster_Data.operational = TestMaster_operational;
		TestMaster_Data.stopped = TestMaster_stopped;
		TestMaster_Data.post_sync = TestMaster_post_sync;
		TestMaster_Data.post_TPDO = TestMaster_post_TPDO;
		TestMaster_Data.post_emcy = TestMaster_post_emcy;
		TestMaster_Data.post_SlaveBootup=TestMaster_post_SlaveBootup;
		TestMaster_Data.post_SlaveStateChange = TestMaster_post_SlaveStateChange;
	}

	// Start timer thread
	StartTimerLoop(&InitNodes);
	return 0;
}

/**
  * @}
  */ 

/**
  * @}
  */ 

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
